package com.hwtx.form.util;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.google.common.collect.Lists;
import com.hwtx.form.controller.PageController;
import com.hwtx.form.domain.def.FormProperties;
import com.hwtx.form.domain.def.Select;
import com.hwtx.form.domain.handle.FormI18nHandle;
import com.hwtx.form.domain.handle.i18n.I18nConfig;
import com.hwtx.form.util.translate.TransApi;
import io.geekidea.boot.framework.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import static com.hwtx.form.util.JacksonUtil.*;
import static io.geekidea.boot.common.constant.SystemConstant.I18N_CONFIG_FILE;
import static java.nio.file.Files.list;

@Slf4j
public class I18nTools {

    static final String regex = "[\\u4e00-\\u9fa5]+";
    static final Pattern pattern = Pattern.compile(regex);

    static final File message = new File("/Users/warning5/pro/spring-lowcode/src/main/resources/i18n/messages.properties");
    static final File zh = new File("/Users/warning5/pro/spring-lowcode/src/main/resources/i18n/messages_zh_CN.properties");
    static final File en = new File("/Users/warning5/pro/spring-lowcode/src/main/resources/i18n/messages_en_US.properties");

    static final Properties bundle = new Properties();
    static final Properties zhBundle = new Properties();
    static final Properties enBundle = new Properties();
    static final TransApi transApi = new TransApi();

    static private final AtomicInteger count = new AtomicInteger(1);

    static {
        try {
            bundle.load(FileUtils.openInputStream(message));
            zhBundle.load(FileUtils.openInputStream(zh));
            enBundle.load(FileUtils.openInputStream(en));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static String getFile(String path) {
        return Objects.requireNonNull(PageController.class.getClassLoader().getResource(path)).getFile();
    }

    public static Stream<Path> listFiles(String path) throws IOException {
        return list(Path.of(getFile(path)));
    }

    public static void main(String[] args) throws Exception {
//        tansAndSave(getFile("i18n/i18n_trans_zh.txt"), true);
//        handleOption(getFile("i18n/i18n_trans_zh.txt"));
//        clearBundle(true);
//        handleMetaInfo(page);
//        handleTypeMapping(getFile("page"));
        String root = "/Users/warning5/pro/spring-lowcode/src/main/resources/page/sys";
        handleFormI18n(Path.of(root, "formConfig_19.json"));
    }

    public static void handleFormI18n(Path file) throws IOException {
        I18nConfig i18nConfig = json2Object(FileUtils.readFileToString(new File(Objects.requireNonNull(I18nTools.class.getClassLoader()
                .getResource("i18n/" + I18N_CONFIG_FILE)).getFile()), StandardCharsets.UTF_8), I18nConfig.class);
        assert i18nConfig != null;
        JsonNode root = JacksonUtil.readJson(Files.readString(file, StandardCharsets.UTF_8));
        FormI18nHandle.handle(root, i18nConfig.getGroup(), (parent, node, property) -> {
            if (!FormUtil.isI18nKey(node.asText()) && containsChinese(node.asText())) {
                if (zhBundle.containsValue(node.asText())) {
                    Map.Entry<Object, Object> item = zhBundle.entrySet().stream().filter(entry -> entry.getValue().equals(node.asText())).findFirst().orElse(null);
                    assert item != null;
                    parent.set(property, TextNode.valueOf("#i18n{" + item.getKey() + "}"));
                    return;
                }
                String key = transZh2En(node.asText(), true);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                parent.set(property, TextNode.valueOf("#i18n{" + key + "}"));
            }
        });
        assert root != null;
        saveBundle();
        Files.writeString(file, root.toPrettyString(), StandardCharsets.UTF_8);
        System.out.println(root.toPrettyString());
    }


    public static String getZh(String key) {
        return zhBundle.getProperty(key);
    }

    public static void handleOption(String page) throws IOException {
        Path file = Paths.get(page);
        List<Select.Option> options = Lists.newArrayList();
        List<String> zhLine = Files.readAllLines(file, StandardCharsets.UTF_8);
        int i = 1;
        for (String line : zhLine) {
            if (line.isEmpty()) {
                continue;
            }
            Map.Entry<Object, Object> target = zhBundle.entrySet().stream().filter(entry -> entry.getValue().equals(line)).findFirst().orElse(null);
            if (target == null) {
                continue;
            }
            Select.Option option = new Select.Option();
            option.setLabel("#i18n{" + target.getKey().toString() + "}");
            option.setValue(i++ + "");
            options.add(option);
        }
        System.out.println(object2json(options));
    }

    public static void clearBundle(boolean clear) throws IOException {
        List<String> keys = Lists.newArrayList();
        zhBundle.forEach((key, value) -> {
            if (!bundle.containsKey(key) || !enBundle.containsKey(key)) {
                log.info("key不完整，需要调整，key = {},value = {}", key, value);
                keys.add(key.toString());
            }
        });
        log.info("需要调整记录数 = {}", keys.size());
        if (clear && !keys.isEmpty()) {
            keys.forEach(key -> {
                zhBundle.remove(key);
                bundle.remove(key);
                enBundle.remove(key);
            });
            saveBundle();
        }
    }

    public static String transZh2En(String name, boolean update) {
        name = name.trim();
        if (name.isEmpty()) {
            return "";
        }
        if (zhBundle.containsValue(name)) {
            log.info("已存在该条记录,跳过,value = {}", name);
            return "";
        }
        String en = transApi.getEnTransResult(name);
        if (StringUtils.isBlank(en)) {
            return "";
        }
        en = en.replaceAll(",", "");
        en = en.trim();
        String key = en.toLowerCase().replace(" ", ".");
        if (zhBundle.containsKey(key)) {
            log.error("key重复,key = {},old = {},new = {}", key, zhBundle.get(key), name);
            return "";
        }
        if (update) {
            zhBundle.put(key, name);
            enBundle.put(key, en);
            bundle.put(key, name);
        }
        log.info("添加国际化信息 key = {},value = {}", key, name);
        return key;
    }


    public static void tansZh2EnAndSave(String path, boolean update) throws IOException {
        Path file = Paths.get(path);
        List<String> zhLine = Files.readAllLines(file, StandardCharsets.UTF_8);
        for (String line : zhLine) {
            transZh2En(line, update);
        }
        saveBundle();
    }

    private static void saveBundle() throws IOException {
        zhBundle.store(FileUtils.openOutputStream(zh), "");
        bundle.store(FileUtils.openOutputStream(message), "");
        enBundle.store(FileUtils.openOutputStream(en), "");
    }

    public static void handleTypeMapping(String page) throws IOException {
        try (Stream<Path> stream = listFiles(page)) {
            stream.filter(path -> path.toFile().getName().equals("org_10.json")).forEach(path -> {
                File file = path.toFile();
                try {
                    JsonNode root = readJson(FileUtils.readFileToString(file, StandardCharsets.UTF_8));
                    assert root != null;
                    traverseNodes(root, "map", List.of(new TraverseMatchRule("map", true)), new FindNodeCallback() {
                        @Override
                        public void handleObjectNode(JsonNode root, ObjectNode node, JsonNode parent, String nodeName) {
                            node.fields().forEachRemaining(entry -> {
                                JsonNode value = entry.getValue();
                                if (value.isTextual()) {
                                    System.out.println(value.asText());
                                }
                            });
                        }
                    });
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

            });
        }
    }

    public static void handleMetaInfo(String page) throws IOException {
        try (Stream<Path> stream = list(Path.of(page))) {
            stream.forEach(path -> {
                File file = path.toFile();
                try {
                    JsonNode root = readJson(FileUtils.readFileToString(file, StandardCharsets.UTF_8));
                    assert root != null;
                    traverseNodes(root, FormProperties.FORM_META, List.of(new TraverseMatchRule(FormProperties.FORM_META, true)),
                            new FindNodeCallback() {
                                @Override
                                public void handleObjectNode(JsonNode root, ObjectNode node, JsonNode parent, String nodeName) {
                                    if (!node.has("title")) {
                                        throw new BusinessException("表单元数据缺少title属性,表单 = " + file.getName());
                                    }
                                    String title = node.get("title").asText();
                                    if (title != null && title.startsWith("#i18n")) {
                                        String key = title.substring(6, title.length() - 1);
                                        try {
                                            outBundleFile(key);
                                        } catch (IOException e) {
                                            throw new RuntimeException(e);
                                        }
                                    }
                                }
                            });
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }

    public static void handleZhInfo(String page) throws IOException {
        try (Stream<Path> stream = list(Path.of(page)).filter(path -> path.toFile().getName().contains("17"))) {
            stream.forEach(path -> {
                try {
                    File file = path.toFile();
                    JsonNode rootNode = readJson(FileUtils.readFileToString(file, StandardCharsets.UTF_8));
                    assert rootNode != null;
                    System.out.println("----------" + path.getFileName() + "----------");
                    traverseJsonNode(rootNode, null, "");
                    System.out.println("---------------End---------------");
                    File out = new File("/Users/warning5/pro/spring-lowcode/src/main/resources/page", file.getName().substring(0, file.getName().lastIndexOf('.')) + ".json");
                    FileUtils.writeStringToFile(out, rootNode.toPrettyString(), StandardCharsets.UTF_8);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }

    private static void traverseJsonNode(JsonNode node, JsonNode parent, String nodeName) throws IOException {
        if (node.isObject()) {
            // 如果节点是对象，遍历其属性
            for (Iterator<String> it = node.fieldNames(); it.hasNext(); ) {
                String fieldName = it.next();
                JsonNode fieldValue = node.get(fieldName);
                Matcher matcher = pattern.matcher(node.asText());
                if (matcher.find()) {
                    System.out.println("Field: " + fieldName + ", Value: " + fieldValue.asText());
                }
                traverseJsonNode(fieldValue, node, fieldName); // 递归遍历子节点
            }
        } else if (node.isArray()) {
            // 如果节点是数组，遍历其元素
            for (JsonNode element : node) {
                traverseJsonNode(element, node, ""); // 递归遍历每个元素
            }
        } else {
            Matcher matcher = pattern.matcher(node.asText());
            boolean hasChinese = matcher.find();
            if (hasChinese) {
                ObjectNode parentNode = (ObjectNode) parent;
                Optional<Map.Entry<Object, Object>> value = bundle.entrySet().stream().filter(entry -> Objects.equals(entry.getValue(), node.asText())).findFirst();
                if (value.isPresent()) {
                    String key = value.get().getKey().toString();
                    if (!key.startsWith("#i18n")) {
                        parentNode.set(nodeName, TextNode.valueOf("#i18n{" + key + "}"));
                    }
                } else {
                    String nodeValue = node.asText();
                    if (!nodeValue.startsWith("#i18n")) {
                        outBundleFile(nodeValue);
                        System.out.println(count.getAndIncrement() + "." + parent + "---->" + node.asText());
                    }
                }

            }
        }
    }

    private static void outBundleFile(String nodeValue) throws IOException {
        if (!zhBundle.containsKey(nodeValue)) {
            zhBundle.put(nodeValue, nodeValue);
            zhBundle.store(FileUtils.openOutputStream(zh), "");
        }
        if (!enBundle.containsKey(nodeValue)) {
            enBundle.put(nodeValue, nodeValue);
            enBundle.store(FileUtils.openOutputStream(en), "");
        }
        if (!bundle.containsKey(nodeValue)) {
            bundle.put(nodeValue, nodeValue);
            bundle.store(FileUtils.openOutputStream(message), "");
        }
    }

    private static boolean containsChinese(String str) {
        // 使用正则表达式判断字符串是否包含中文字符
        return str != null && regexMatch(str);
    }

    private static boolean regexMatch(String str) {
        return str.matches(".*" + "[一-\u9fff]" + ".*");
    }

}